package com.pkk.components.util.spring;

import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.ConfigurableApplicationContext;

/**
 * @description: 动态注册bean
 * @author: peikunkun
 * @create: 2019-06-15 18:36
 **/
public class SpringRegisterBean {

  /**
   * 主动向Spring容器中注册bean
   *
   * @param applicationContext Spring容器
   * @param beanName BeanName
   * @param registerBeanClazz 将要注册的bean的类
   * @param constructorArges 构造方法的必要参数，顺序和类型要求和clazz中定义的一致
   * @return 返回注册到容器中的bean对象
   */
  public static <T> T registerBean(ConfigurableApplicationContext applicationContext, String beanName,
      Class<T> registerBeanClazz,
      Object... constructorArges) {
    //容器中是否已经包含此bean
    if (applicationContext.containsBean(beanName)) {
      Object bean = applicationContext.getBean(beanName);

      //的类或接口是否相同，或是否是其超类或超接口。如果是则返回 true；否则返回 false。如果该 Class 表示一个基本类型，且指定的 Class 参数正是该 Class 对象，则该方法返回 true；否则返回 false
      if (bean.getClass().isAssignableFrom(registerBeanClazz)) {
        return (T) bean;
      } else {
        throw new RuntimeException("BeanName 重复 " + beanName);
      }
    }

    //Spring的bean的定义构造器
    BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(registerBeanClazz);
    //给要注册的bean设置构造函数相应的参数,注意,顺序要相同
    for (Object arg : constructorArges) {
      beanDefinitionBuilder.addConstructorArgValue(arg);
    }
    //获取原始的bean
    BeanDefinition beanDefinition = beanDefinitionBuilder.getRawBeanDefinition();
    //获取bean定义注册的工厂
    BeanDefinitionRegistry beanFactory = (BeanDefinitionRegistry) applicationContext.getBeanFactory();
    //开启注册bean到Sring容器中
    beanFactory.registerBeanDefinition(beanName, beanDefinition);
    return applicationContext.getBean(beanName, registerBeanClazz);
  }
}
